#include <iostream>
#include <ctime>
#include <iomanip>
#include <graphics.h>
#include <math.h>


using namespace std;
bool specification;
//*****************************************************************************
// PRINT ARRAY ****************************************************************
void printarray(double **myarray,int m)
{
    for (int count_row = 0; count_row < m; count_row++)
    {
        for (int count_column = 0; count_column < m; count_column++)    
            cout << setw(7) << fixed << setprecision(4) << myarray[count_row][count_column] << "   ";             
        cout << " |  "<< myarray[count_row][m] << endl;
    } 
    cout<<endl;   
}
// ****************************************************************************
// DET (A) ********************************************************************
double DetA(double **getarray,int m,int count_frow)
{
    double det=0; 
    
    if (m == 2) 
       det += getarray[0][0] * getarray[1][1] - getarray[0][1] * getarray[1][0];
    else
    {
        // hacemos el tamano de la masiv M-1 x M-1
        double **setarray = new double* [m-1];  
        for (int count = 0; count < m-1; count++) setarray[count] = new double [m-1]; 
        
        for (int count_frow=0;count_frow<m;count_frow++)
        {
            for (int count_row=1;count_row<m;count_row++)
            {
                int colum=0;
                for (int count_column=0;count_column<m;count_column++)
                    if(count_column!=count_frow)
                        setarray[count_row-1][count_column-colum]=getarray[count_row][count_column];       
                    else colum = 1;    
            }  
            if (count_frow%2==1)
               det-=getarray[0][count_frow]*DetA(setarray,m-1,count_frow);
            else
               det+=getarray[0][count_frow]*DetA(setarray,m-1,count_frow); 
        }
        for (int count = 0; count < m-1; count++)
            delete []setarray[count];                                  
    }
    return det;          
}
//*****************************************************************************
// SLAU ***********************************************************************
double slau(double **myarray,int m)
{      
         double oper=0;       
         // convertimos la matriz a su forma triangular
         for(int count=0;count<m;count++ )
         {
            oper=myarray[count][count]; 
            if(specification) cout<<"Devide "<<count+1<<" line "<<oper<<endl;    
            for(int count_colum=0;count_colum<=m;count_colum++)
               myarray[count][count_colum]=myarray[count][count_colum]/oper;
            if(specification) printarray(myarray,m);
            
            for(int count_row=0;count_row<m;count_row++)
               if(count!=count_row)
               {  
                  oper=myarray[count_row][count];                                  
                  if(specification) cout<<count_row+1<<" lines subtract "<<count+1<<" "<<oper<<" multiplied"<<endl;                 
                  for(int count_colum=0;count_colum<=m;count_colum++)            
                     myarray[count_row][count_colum]=myarray[count_row][count_colum]-(myarray[count][count_colum]*oper);  
                  if(specification) printarray(myarray,m);        
               }     
         }
         // obtenemos las variables desconocidas
         for(int count=0;count<m;count++ )
             cout << "x" << count+1 << " = " << fixed << setprecision(14) << myarray[count][m]<<endl; 
                                    
}
//*****************************************************************************
// EPSILON ********************************************************************
double epsilon(int m,double e)
{   
    double returned=0;   
    double **myarray = new double* [m]; 
     
    for (int count = 0; count < m; count++) myarray[count] = new double [m+1];
    
    for (int count_row = 0; count_row < m; count_row++)
    {    
         for (int count_column = 0; count_column < m; count_column++)   
            if (count_column==count_row) myarray[count_row][count_column]=1+e;
            else if (count_column>count_row) myarray[count_row][count_column]=1-e;                          
            else if (count_column<count_row) myarray[count_row][count_column]=e;
        
         if (count_row<m-1) myarray[count_row][m]=-1;
         else myarray[count_row][m]=1+e;
    }
    
    cout<<endl<<"EPSILON (e<0.001) "<<endl;      
    printarray(myarray,m);
    slau(myarray,m);
    
    for (int count_row = 0; count_row < m; count_row++)
        returned+=pow(myarray[count_row][m],2);    
    
    for (int count = 0; count < m; count++)
        delete []myarray[count];    
    return returned;           
}
//*****************************************************************************
// Visual representation GRAPHICS *********************************************
void graphics(int z)
{    
     int DRIVER=DETECT, MODE; 
     double OPER=0,e1=0.001,e2=1.5;
     initgraph(&DRIVER,&MODE,"");   
     
     setcolor(13);
     rectangle(10, 10, getmaxx()-10, getmaxy()-10);
     
     moveto((int)(getmaxx()*0.15), (int)(getmaxy()*0.8));
     lineto((int)(getmaxx()*0.85), (int)(getmaxy()*0.8));
     lineto((int)(getmaxx()*0.85)-5, (int)(getmaxy()*0.8)-5);
     lineto((int)(getmaxx()*0.85)-5, (int)(getmaxy()*0.8)+5);
     lineto((int)(getmaxx()*0.85), (int)(getmaxy()*0.8));
     
     moveto((int)(getmaxx()*0.15), (int)(getmaxy()*0.8));
     lineto((int)(getmaxx()*0.15), (int)(getmaxy()*0.2));
     lineto((int)(getmaxx()*0.15)-5, (int)(getmaxy()*0.2)+5);
     lineto((int)(getmaxx()*0.15)+5, (int)(getmaxy()*0.2)+5);
     lineto((int)(getmaxx()*0.15), (int)(getmaxy()*0.2));        
     
     outtextxy(220,70,"* Visual representation *");  
     outtextxy((int)(getmaxx()*0.85)+10,(int)(getmaxy()*0.8)-10,"X"); 
     outtextxy((int)(getmaxx()*0.15)+10,(int)(getmaxy()*0.2)-10,"Y");
     
     if(z==1) 
     {          
         for(int m=2;m<40;m++)
         {
               OPER = epsilon(m,e1);
               OPER = pow(OPER,0.5)/m;
               fillellipse((int)(getmaxx()*0.15)+m*10,(int)(getmaxy()*0.8)-(int)(OPER*200),3,3);
         }
     }    
     if (z==2)
     { 
         for(int m=2;m<30;m++)
         {
               OPER = epsilon(m,e2);
               OPER = 1/pow(OPER,0.5);
               fillellipse((int)(getmaxx()*0.15)+m*10,(int)(getmaxy()*0.8)-(int)(OPER*200),3,3);
               e2 = e2 / 1.5;
         }  
     }        
}
//*****************************************************************************
// myarray **************************************************************
void setarray(double **myarray)
{
    myarray[0][0] = 3.8;
    myarray[0][1] = 1;
    myarray[0][2] = 1;
    myarray[0][3] = 1;

    myarray[1][0] = 1;
    myarray[1][1] = 5.8;
    myarray[1][2] = 1;
    myarray[1][3] = 1;

    myarray[2][0] = 1;
    myarray[2][1] = 1;
    myarray[2][2] = 7.8;
    myarray[2][3] = 1;

    myarray[3][0] = 1;
    myarray[3][1] = 1;
    myarray[3][2] = 1;
    myarray[3][3] = 9.8; 
   
    myarray[0][4] = 9;
    myarray[1][4] = 11;
    myarray[2][4] = 13;
    myarray[3][4] = 15;
}
//*****************************************************************************
// Simle iteration ************************************************************


//*****************************************************************************
// MAIN FUNCTION **************************************************************
int main(int argc, char *argv[])
{
    int m; double det = 0,e=0.001; char c; 
    srand(time(0)); 
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE );
    
    cout<<"Enter the dimension of the matrix: ";
    cin>>m; // ponemos el tamano de la matriz
    cout<<"Show calculation specification?(y/n): ";
    cin>>c; cout<<endl;
    
    switch(c)
    {
     case 'y': specification = true; break;
     default: specification = false;         
    }
    
    // hacemos el tamano de la masiv M x M
    double **myarray = new double* [m];  
    for (int count = 0; count < m; count++) myarray[count] = new double [m+1];  
    
    // llenamos la matriz doble de numeros
    for (int count_row = 0; count_row < m; count_row++)
        for (int count_column = 0; count_column <= m; count_column++)
            //myarray[count_row][count_column] = rand() % 10 ;
            myarray[count_row][count_column] = (rand() % 10 + 1) / float((rand() % 10 + 1));
 
    setarray(myarray);        
    
    printarray(myarray,m);
    
    det = DetA(myarray,m,0);
    
    // checamos el determinante con la igualdad 0
    if(det!=0)
    {
         cout<<" det(A) = "<<setprecision(4)<<det<<endl<<endl;     
         slau(myarray,m);  
         epsilon(m,e);
         
         system("PAUSE");
         
         graphics(1);
         system("PAUSE"); 
         graphics(2);  
         system("PAUSE");          
    }     
    else
       cout<<" No decision! det(A) = "<<setprecision(4)<<det<<endl<<endl; 
               
    system("PAUSE");   
      
    // limpiamos la memoria debajo de lamatriz
    for (int count = 0; count < m; count++)
        delete []myarray[count];
    
    closegraph();               
    return EXIT_SUCCESS;
}
